package serveur;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.sql.*;
import data.*;

public class ServeurUDP 
{	
	private final String AUTHENTIFICATION = "data.AuthentificationData";
	private final String CHAUFFAGE  = "data.Chauffage";
	private final String STORES = "data.Stores";
	private final String COLLECTIONITEMS = "data.CollectionItemData";
	private final String COLLECTIONPIECES = "java.util.ArrayList"; 
	private InetAddress destinationAdress = null;
	private int destinationPort = 0;
	private DatagramSocket socket = null;
	private int localPort = 32665;
	private String etat;
	private Connection connexionBdd;
	
	public ServeurUDP() 
	{
		try
	    {
			//Si on est sur le serveur central mettre "jdbc:mysql://localhost/domotique"
			//Si on est sur le serveur foyer mettre "jbdc:mysql://localhost/domotiqueFoyer"
			Connection connexion = DriverManager.getConnection("jbdc:mysql://localhost/domotiqueFoyer,"root","Baltosss1989");
	    	socket = new DatagramSocket(localPort);
	    	socket.setSoTimeout(0); // receive bloquant jusqu'a r�ception d'un paquet
	    	etat = "stop";
	    }
	    catch(SocketException e) 
		{
			exit(1);		
		}
		catch(SQLException e)
		{
			exit(2);	
		}
	}
	
	public void startServeur()
	{
		etat = "run";
		System.out.println("D�marrage du serveur");
		Object data = new AuthentificationData();
		ArrayList <String> a = new ArrayList <String>();
		System.out.println(a.getClass().getName());
		if (data.getClass().getName().equals(AUTHENTIFICATION))
		{
			gestion((AuthentificationData)data);
		}
		else
		{
			System.out.println("GROS FAIL");
		}
		
		
		/*while(etat.equals("run"))
		{
			//data = receiveData();
			if (data.getClass().getName().equals(AUTHENTIFICATION))
			{
				
			}
		}*/
	}
	
	public void stopServeur()
	{
		etat = "stop";
	}
	
	public Object receiveData()
	{
		byte[] buffer = new byte[1024];
		DatagramPacket p = new DatagramPacket(buffer, buffer.length);
		try
		{
			socket.receive(p);
		}
		catch(IOException e)
		{
			return null;
		}
		
		destinationAdress = p.getAddress(); //on r�cup�re l'adresse de l'�metteur du paquet
		destinationPort = p.getPort(); // on r�cup�re le port de l'�metteur du paquet
		
		ByteArrayInputStream input = new ByteArrayInputStream(buffer);
		try
		{
			ObjectInputStream oos = new ObjectInputStream(input);
			try
			{
				return oos.readObject();
			}
			catch (IOException e)
			{
				return null;
			}
			catch(ClassNotFoundException e) 
			{
				return null;
			}
			finally
			{
				oos.close();
				input.close();
			}
		}
		catch(IOException e)
		{
			return null;
		}		
	}
	
	public int sendData(Object tosend)
	{	
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		try
		{
			ObjectOutputStream oos = new ObjectOutputStream(output);
			try
			{
				oos.writeObject(tosend);
			}
			catch (IOException e)
			{
				oos.close();
				output.close();
			}
		}	
		catch (IOException e)
		{
			return -1;
		}
		
		DatagramPacket p = new DatagramPacket(output.toByteArray(), output.toByteArray().length, destinationAdress, destinationPort);
		try
		{		
			socket.send(p);
		}
		catch(IOException e)
		{
			return -1;
		}
		return 0;
	}

	/*
	 * gestion(Chauffage) : fonction permettant de remplir ou modifier un chauffage.
	 * data : variable de type Chauffage. Cette variable doit avoir au minimum data.id de connu. 
	 * Si data.temperature!=-1 alors on modifie la maison, sinon on rempli data avec l'état actuel du chauffage.
	 * Renvoie un Chauffage remplie avec l'état actuel de la maison (après modification si nécessaire).
	 */
	public Chauffage gestion(Chauffage data)
	{
		//instancier le chauffage X de la base de donn�es ayant pour id : data.getId()
		Chauffage X= new Chauffage();
		try
		{
			Statement stmt = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
			ResultSet rs = stmt.executeQuery("SELECT * FROM Chauffage WHERE ID_Chauffage="+data.getId());
			if(rs.getFetchSize()>0)
			{
				while(rs.next())
				{
					X.setId(rs.getString("ID_Chauffage"));
					X.setTemperature((float)(rs.getInt("Temperature")));
					X.setTemperatureMax((float)(rs.getInt("TemperatureMax")));
					X.setTemperatureMin((float)(rs.getInt("TemperatureMin")));
				}
			}
			//si la modification de temperature est autoris� et si data n'est pas vide (temperature !=-1) alors modifi� bdd avec nouvelle temperature
			if((data.getTemperature()<=X.getTemperatureMin())&&(data.getTemperature()>=X.getTemperatureMax())&&(data.getTemperature()!=-1))
			{
				stmt = connexionBdd.createStatement();
				stmt.executeUpdate("UPDATE Chauffage SET Temperature = "+data.getTemperature()+" WHERE ID_Chauffage = "+data.getId());
			}
			//sinon data.setTemperature(X.getTemperature) (on renvoie l'état actuel de la maison)
			else
			{
				data.setId(X.getId());
				data.setTemperature(X.getTemperature);
				data.setTemperatureMin(X.getTemperatureMin());
				data.setTemperatureMax(X.getTemperatureMax());
			}
		}
		catch(SQLException e)	//Si on a une erreur on renvoie un Chauffage vide...
		{
			e.printStackTrace();
			return new Chauffage();
		}
		return data;
	}
	
	/*
	 * gestion(Stores) : fonction permettant de remplir ou modifier un store.
	 * data : variable de type Stores. Cette variable doit avoir au minimum data.id de connu. 
	 * Si data.position!=-1 alors on modifie la maison, sinon on rempli data avec l'état actuel du store.
	 * Renvoie un Stores remplie avec l'état actuel de la maison (après modification si nécessaire).
	 */
	public Stores gestion(Stores data)
	{
		//meme fonctionnement
		Stores X = new Stores();
		try
		{
			Statement stmt = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
			ResultSet rs = stmt.executeQuery("SELECT * FROM Stores WHERE ID_Stores="+data.getId());
			if(rs.getFetchSize()>0)
			{
				while(rs.next())
				{
					X.setId(data.getId());
					X.setPosition(rs.getInt("Position"));
				}
			}
			if(data.getPosition()!=-1)	//Si on veut modifier la maison
			{
				stmt = connexionBdd.createStatement();
				stmt.executeUpdate("UPDATE Stores SET Position = "+data.getPosition()+" WHERE ID_Stores="+data.getId());
			}
			else	//Si on veut récupérer l'état actuel de la maison
			{
				data.setId(X.getId());
				data.setPosition(X.getPosition);
			}
		}
		catch(SQLException e)
		{
			e.printStackTrace();
			return new Stores();
		}
		return data;
	}
	
	/*
	 * gestion(CollectionItemData) : fonction permettant de remplir ou modifier les éléments d'une pièce.
	 * data : variable de type CollectionItemData. Cette variable doit avoir au minimum data.lieu de connu. 
	 * Si data.items est rempli alors on modifie la maison, sinon on rempli data.items avec l'état actuel de la pièce.
	 * Renvoie un CollectionItemData remplie avec l'état actuel de la maison (après modification si nécessaire).
	 */
	public CollectionItemData gestion(CollectionItemData data)
	{
		//fonctionnement similaire
		//data.setItems(gestion(data.getItems()[i]));
		String piece = data.getLieu();
		if(piece!="")
		{
			try
			{
				Statement stmt = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
				ResultSet elem = stmt.executeQuery("SELECT * FROM Element WHERE Nom_Piece = "+piece);
				while(elem.next())
				{
					Statement stmt2 = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
					ResultSet chauff = stmt2.executeQuery("SELECT * FROM Chauffage WHERE ID_Element ="+elem.getString("ID_Element"));
					if(chauff.getFetchSize()>0)
					{
						chauff.next();
						Chauffage chauffage = new Chauffage(chauff.getString("ID_Chauffage"), chauff.getInt("Etat"), (float)(chauff.getInt("Temperature")), (float)(chauff.getInt("TemperatureMax")), (float)(chauff.getInt("TemperatureMin")));
						data.setItems(gestion(chauffage));
					}
					else
					{
						stmt2 = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
						ResultSet stores = stmt2.executeQuery("SELECT * FROM Stores WHERE ID_Element ="+elem.getString("ID_Element"));
						if(stores.getFetchSize()>0)
						{
							stores.next();
							Stores store = new Stores(stores.getString("ID_Stores"),0, stores.getString("Position"));
							data.setItems(gestion(store));
						}
						else
						{
							return new CollectionItemData();
						}
					}
				}
			}
			catch(SQLException e)
			{
				e.printStackTrace();
				return new CollectionItemData();
			}
			return data;
		}
		else return new CollectionItemData();
	}
	
	/*
	 * gestion(ArrayList<String>) : fonction permettant de récupérer la liste des pièces.
	 * Renvoie un ArrayList<String>
	 */
	public ArrayList<String> gestion(ArrayList<String> data)
	{
		try
		{
			Statement stmt = connexionBdd.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
			ResultSet rs = stmt.executeQuery("SELECT * FROM Piece");
			while(rs.next())
			{
				data.add(rs.getString("Nom_Piece"));
			}
		}
		catch(SQLException e)
		{
			e.printStackTrace();
			return new ArrayList<String>();
		}
		return data;
	}	
}
